﻿using System;
using System.Collections.Generic;

namespace Jinndev {

    public class Counter<K> : IEquatable<Counter<K>> {

        public interface AddCounter {
            void Add(Counter<K> counter);
        }

        private Dictionary<K, int> dict = new Dictionary<K, int>();

        /// <summary>
        /// 自动移除值为0的key，默认true
        /// </summary>
        public bool removeZeroKey;

        public Counter(bool removeZeroKey = true) {
            this.removeZeroKey = removeZeroKey;
        }

        public Counter(K key, int value, bool removeZeroKey = true) {
            this.removeZeroKey = removeZeroKey;
            Add(key, value);
        }

        public Counter(AddCounter obj, bool removeZeroKey = true) {
            this.removeZeroKey = removeZeroKey;
            obj.Add(this);
        }

        public Counter(Counter<K> another) {
            removeZeroKey = another.removeZeroKey;
            foreach (var pair in another.dict) {
                dict[pair.Key] = pair.Value;
            }
        }

        public int this[K key] {
            get {
                if(dict.TryGetValue(key, out int num)) {
                    return num;
                }
                return 0;
            }
            set {
                if (dict.ContainsKey(key)) {
                    if(value == 0) {
                        dict.Remove(key);
                    }
                    else {
                        dict[key] = value;
                    }
                }
                else if (value != 0) {
                    dict.Add(key, value);
                }
            }
        }

        public int Add(K key, int num = 1) {
            num += this[key];
            this[key] = num;
            return num;
        }

        public IEnumerable<K> Keys {
            get { return dict.Keys; }
        }

        public void Add(Counter<K> other) {
            foreach(K key in other.Keys) {
                Add(key, other[key]);
            }
        }

        public void Remove(Counter<K> other) {
            foreach (K key in other.Keys) {
                Add(key, -other[key]);
            }
        }

        public void Sync(Counter<K> other) {
            foreach (K key in other.Keys) {
                this[key] = other[key];
            }
        }

        public bool IsAllZero() {
            foreach(int num in dict.Values) {
                if(num != 0) {
                    return false;
                }
            }
            return true;
        }

        public bool Equals(Counter<K> other) {
            if (other != null) {
                foreach (K key in other.Keys) {
                    if (this[key] != other[key]) {
                        return false;
                    }
                }
            }
            return true;
        }

        public override string ToString() {
            string[] str = new string[dict.Count];
            int i = 0;
            foreach(var pair in dict) {
                str[i] = pair.Key + "*" + pair.Value;
                i++;
            }
            return "(" + string.Join(", ", str) + ")";
        }

        //public object Clone() {
        //    Counter<K> clone = new Counter<K>(removeZeroKey);
        //    foreach (var pair in dict) {
        //        clone[pair.Key] = pair.Value;
        //    }
        //    return clone;
        //}

        public static Counter<K> operator *(Counter<K> counter, int num) {
            Counter<K> newCounter = new Counter<K>(counter.removeZeroKey);
            foreach(var pair in counter.dict) {
                newCounter.dict[pair.Key] = pair.Value * num;
            }
            return newCounter;
        }

        // 容易死循环，还是用Equals

        //public static bool operator ==(Counter<K> lhs, Counter<K> rhs) {
        //    return lhs.Equals(rhs);
        //}

        //public static bool operator !=(Counter<K> lhs, Counter<K> rhs) {
        //    return !lhs.Equals(rhs);
        //}

    }


}